/*=====================================================
Critical Links
Auto Configuration Server

Authors:
	Rui Eduardo Gouveia Gil - r-gil@critical-links.com

Date: 2010
Version 0.1
=======================================================*/
#include "httpd/SConfigurations.h"
#include "database/DataBase.h"
#include "ACSConfig.h"

namespace acs
{

std::vector<std::string> SConfigurations::getHtml(std::string divID, std::string query)
{
	if(query.empty())
		return SConfigurations::getConfigurationListHtml(divID,"");
	else
	{
		rgcpp::StringTokenizer tokenizer(query,'#');

		std::string action = tokenizer.nextToken();
		if(action.compare(SC_ACTION_NEW) == 0)
			return SConfigurations::getNewConfigurationHtml(divID);
		else if(action.compare(SC_ACTION_SHOW) ==  0 && tokenizer.hasMoreElements())
			return SConfigurations::getConfigurationHtml(divID,tokenizer.nextTokenInt());
		else if(action.compare(SC_ACTION_EDIT) == 0 && tokenizer.hasMoreElements())
			return SConfigurations::getEditConfigurationHtml(divID,tokenizer.nextTokenInt());
		else
			return SConfigurations::getConfigurationListHtml(divID,query);
	}
}

std::vector<std::string> SConfigurations::addConfigurationCommand(std::string divID, int configurationID, std::string command)
{
	std::vector<std::string> result;

	if(!DataBase::getInstance()->existsConfiguration(configurationID))
	{
		result.push_back(divID);
		result.push_back("");
		result.push_back("window.location = '/configurations.html';");
		return result;
	}

	boost::trim(command);

	if(!command.empty())
	{
		rgcpp::StringTokenizer tokenizer(command,' ');

		std::string cmd = tokenizer.nextToken();
		std::vector<std::string> args;
		while(tokenizer.hasMoreElements())
			args.push_back(tokenizer.nextToken());

		DataBase::getInstance()->addConfigurationCommand(Command(configurationID,cmd,args));
	}

	result.push_back(divID);
	result.push_back(SConfigurations::getConfigurationCommandHtml(configurationID));
}

std::vector<std::string> SConfigurations::switchConfigurationCommand(std::string divID, int configurationID, int index1, int index2)
{
	std::vector<std::string> result;

	if(!DataBase::getInstance()->existsConfiguration(configurationID))
	{
		result.push_back(divID);
		result.push_back("");
		result.push_back("window.location = '/configurations.html';");
		return result;
	}

	DataBase::getInstance()->switchConfigurationCommandIndex(configurationID,index1,index2);

	result.push_back(divID);
	result.push_back(SConfigurations::getConfigurationCommandHtml(configurationID));
}

std::vector<std::string> SConfigurations::removeConfigurationCommand(std::string divID, int configurationID, int index)
{
	std::vector<std::string> result;

	if(!DataBase::getInstance()->existsConfiguration(configurationID))
	{
		result.push_back(divID);
		result.push_back("");
		result.push_back("window.location = '/configurations.html';");
		return result;
	}

	DataBase::getInstance()->removeConfigurationCommand(configurationID,index);

	result.push_back(divID);
	result.push_back(SConfigurations::getConfigurationCommandHtml(configurationID));
}

std::vector<std::string> SConfigurations::createConfiguration(std::string name, std::string description)
{
	std::stringstream stream;
	std::vector<std::string> result;

	if(name.empty())
	{
		result.push_back("errorMessage");
		result.push_back("<span class=\"loginMessageError\">Invalid configuration name!</span>");
		result.push_back("$('confName').style.borderColor = '#CC0505';");
	}
	else if(DataBase::getInstance()->existsConfiguration(name))
	{
		result.push_back("errorMessage");
		result.push_back("<span class=\"loginMessageError\">The configuration name is already in use! Please choose a different one.!</span>");
		result.push_back("$('confName').style.borderColor = '#CC0505';");
	}
	else
	{
		try
		{
			Configuration configuration;
			configuration.setName(name);
			configuration.setDescription(description);

			configuration = DataBase::getInstance()->createConfiguration(configuration);

			stream << "window.location = '/configurations.html#show#" << configuration.getID() << "';";

			result.push_back("errorMessage");
			result.push_back("<span class=\"loginMessageError\"></span>");
			result.push_back(stream.str());
		}
		catch (rgcpp::Exception& e)
		{
			result.push_back("errorMessage");
			result.push_back("<span class=\"loginMessageError\">Server Internal Error! Please check the logs for more information.</span>");
		}
	}

	return result;
}

std::vector<std::string> SConfigurations::saveConfiguration(int configurationID, std::string name, std::string description)
{
	std::stringstream stream;
	std::vector<std::string> result;

	if(!DataBase::getInstance()->existsConfiguration(configurationID))
	{
		result.push_back("errorMessage");
		result.push_back(stream.str());
		result.push_back("window.location = '/configurations.html';");
		return result;
	}

	Configuration configuration = DataBase::getInstance()->getConfiguration(configurationID);

	if(name.empty())
	{
		result.push_back("errorMessage");
		result.push_back("<span class=\"loginMessageError\">Invalid configuration name!</span>");
		result.push_back("$('confName').style.borderColor = '#CC0505';");
	}
	else if(DataBase::getInstance()->existsConfiguration(name) && configuration.getName().compare(name) != 0)
	{
		result.push_back("errorMessage");
		result.push_back("<span class=\"loginMessageError\">The configuration name is already in use! Please choose a different one.!</span>");
		result.push_back("$('confName').style.borderColor = '#CC0505';");
	}
	else
	{
		try
		{
			configuration.setName(name);
			configuration.setDescription(description);

			DataBase::getInstance()->updateConfiguration(configuration);

			stream << "window.location = '/configurations.html#show#" << configuration.getID() << "';";

			result.push_back("errorMessage");
			result.push_back("<span class=\"loginMessageError\"></span>");
			result.push_back(stream.str());
		}
		catch (rgcpp::Exception& e)
		{
			result.push_back("errorMessage");
			result.push_back("<span class=\"loginMessageError\">Server Internal Error! Please check the logs for more information.</span>");
		}
	}

	return result;
}

std::vector<std::string> SConfigurations::removeConfiguration(int configurationID)
{
	std::vector<std::string> result;

	if(	DataBase::getInstance()->getConfigurationDevicesCount(configurationID) != 0)
	{
		result.push_back(std::string("alert('Unable to delete this configuration. It is in use by a device.'); window.location = '/configurations.html#show#")+rgcpp::ToString(configurationID)+std::string("';"));
	}
	else
	{
		DataBase::getInstance()->removeConfiguration(configurationID);
		result.push_back("window.location = '/configurations.html';");
	}

	return result;
}

std::vector<std::string> SConfigurations::clearConfigurationBackupRestoreFile(std::string divID, int configurationID)
{
	std::stringstream stream;
	std::vector<std::string> result;

	if(!DataBase::getInstance()->existsConfiguration(configurationID))
	{
		result.push_back(divID);
		result.push_back(stream.str());
		result.push_back("window.location = '/configurations.html';");
		return result;
	}

	Configuration configuration = DataBase::getInstance()->getConfiguration(configurationID);
	configuration.setConfigFileName("");
	DataBase::getInstance()->updateConfiguration(configuration);

	stream << "			<span class=\"head2\">Backup/Restore File</span><br/><br/>";
	stream << "			<form method=\"POST\" enctype=\"multipart/form-data\" action='/FileUpload?type=1&id=" << configurationID << "'>";
	stream << "				<span class=\"head3\">Upload new file:&nbsp;</span>";
	stream << "				<input id=\"upfile\" name=\"upfile\" type=\"file\" class=\"text\" />&nbsp;&nbsp;<input type=\"submit\" value=\"Upload\" style=\"width:60px;\"/>";
	stream << "			</form>";

	stream << "			<br/>";

	result.push_back(divID);
	result.push_back(stream.str());

	return result;
}

std::vector<std::string> SConfigurations::getConfigurationListHtml(std::string divID, std::string text)
{
	std::stringstream stream;
	std::vector<std::string> result;

	stream << "<table width=\"1024\">";
	stream << "	<tr><td>";

	stream << "		<br/>";

	stream << "		<div style=\"overflow: hidden; margin-left: 10px;\">";
	stream << "			<span class=\"head1\">Configurations :: List</span><br/>";
	stream << "		</div>";
	stream << "		<div style=\"overflow: hidden;\">";
	stream << "			<a href=\"javascript: $('loading').style.visibility='visible'; window.location = '/configurations.html#'+$('searchInputText').value;\" class=\"searchImage\" style=\"float:right;\"></a>";
	stream << "			<input id=\"searchInputText\" type=\"text\" class=\"searchInput\" style=\"float:right;\" value=\"" << text << "\" onkeypress=\"javascript: if(checkEnter(event)){$('loading').style.visibility='visible'; window.location = '/configurations.html#'+$('searchInputText').value;}\"/>";
	stream << "			<span style=\"float:left; margin-left: 20px; margin-top: 5px;\"><a href=\"/configurations.html#new\" class=\"textLink\">[new configuration]</a></span>";
	stream << "		</div>";

	stream << "		<hr/>";

	std::vector<Configuration> configurations = DataBase::getInstance()->listConfigurations(text);

	if(configurations.empty())
	{
		stream << "	<div style=\"overflow: hidden; margin-left: 20px;\">";
		if(text.empty())
			stream << "<span class=\"text\">No results found...</span>";
		else
			stream << "<span class=\"text\">No results found for: " << text <<"</span>";
		stream << "	</div>";
	}
	else
	{
		  char buffer [80];

		stream << "	<div style=\"overflow: hidden; margin-left: 20px;\">";
		stream << "		<table width=\"1004\">";
		stream << "		<tr class=\"tableRowHeader\">";
		stream << "			<td>Name</td><td>Type</td><td>Release</td><td>Created On</td><td>Updated On</td><td>Used By</td>";
		stream << "		</tr>";
		for(std::vector<Configuration>::iterator itr=configurations.begin(); itr!=configurations.end(); itr++)
		{
			stream << "		<tr cellpadding=\"0\" cellspacing=\"0\" class=\"tableRow\" onmouseover=\"javascript: document.body.style.cursor = 'pointer';\" onmouseout=\"javascript: document.body.style.cursor = 'default';\" onclick=\"javascript: window.location = '/configurations.html#show#" << itr->getID() << "'; document.body.style.cursor = 'default';\">";
			stream << "			<td style=\"width: 200px;\">" << itr->getName() << "</td><td>" << itr->getCFType() << "</td><td>" << itr->getCFRelease() << "</td><td>" << rgcpp::ToString(itr->getCreation(),"%Y-%m-%d %X") << "</td><td>" << rgcpp::ToString(itr->getUpdated(),"%Y-%m-%d %X") << "</td><td>" << DataBase::getInstance()->getConfigurationDevicesCount(itr->getID()) << "</td>";
			stream << "		</tr>";
		}
		stream << "		</table>";
		stream << "	</div>";
	}

	stream << "		<hr/>";

	stream << "	</td></tr>";
	stream << "</table>";

	result.push_back(divID);
	result.push_back(stream.str());

	return result;
}

std::vector<std::string> SConfigurations::getNewConfigurationHtml(std::string divID)
{
	std::stringstream stream;
	std::vector<std::string> result;

	stream << "<table width=\"1024\">";
	stream << "	<tr><td>";

	stream << "		<br/>";

	stream << "		<div style=\"overflow: hidden; margin-left: 10px;\">";
	stream << "			<span class=\"head1\">Configurations :: New</span><br/>";
	stream << "		</div>";

	stream << "		<hr/>";

	stream << "<table style=\"margin-left: 20px;\">";
	stream << "	<tr style=\"height: 30px\">";
	stream << "		<td valign=\"top\">";
	stream << "			<span class=\"head3\">Name:&nbsp;&nbsp;&nbsp;</span><br/>";
	stream << "		</td>";
	stream << "		<td>";
	stream << "			<input class=\"inputText\" type=\"text\" id=\"confName\" name=\"confName\" value=\"\" /><br/>";
	stream << "		</td>";
	stream << "	</tr>";
	stream << "	<tr style=\"height: 30px\">";
	stream << "		<td valign=\"top\">";
	stream << "			<span class=\"head3\">Description:&nbsp;&nbsp;&nbsp;</span><br/>";
	stream << "		</td>";
	stream << "		<td>";
	stream << "			<textarea class=\"inputTextArea\" type=\"text\" id=\"confDescription\" name=\"confDescription\" rows=\"4\" ></textarea><br/>";
	stream << "		</td>";
	stream << "	</tr>";
	stream << "	<tr style=\"height: 30px\">";
	stream << "		<td></td>";
	stream << "		<td align=\"center\">";
	stream << "			<input type=\"button\" value=\"Create\" style=\"width:60px;\" onclick=\"javascript: $('loading').style.visibility='visible'; SConfigurations.createConfiguration($('confName').value,$('confDescription').value,redrawLayer)\" />&nbsp;&nbsp;|&nbsp;&nbsp;<a href=\"/configurations.html\" class=\"cancelLink\">Cancel<a>";
	stream << "		</td>";
	stream << "	</tr>";
	stream << "</table>";
	stream << "	<br/>";
	stream << "	<div id=\"errorMessage\"></div></";
	stream << "	<br/>";
	stream << "	</td></tr>";
	stream << "</table>";

	result.push_back(divID);
	result.push_back(stream.str());

	return result;
}

std::vector<std::string> SConfigurations::getEditConfigurationHtml(std::string divID, int configurationID)
{
	std::stringstream stream;
	std::vector<std::string> result;

	if(!DataBase::getInstance()->existsConfiguration(configurationID))
	{
		result.push_back(divID);
		result.push_back(stream.str());
		result.push_back("window.location = '/configurations.html';");
		return result;
	}

	Configuration configuration = DataBase::getInstance()->getConfiguration(configurationID);

	stream << "<table width=\"1024\">";
	stream << "	<tr><td>";

	stream << "		<br/>";

	stream << "		<div style=\"overflow: hidden; margin-left: 10px;\">";
	stream << "			<span class=\"head1\">Configurations :: " << configuration.getName() << " :: Edit</span><br/>";
	stream << "		</div>";

	stream << "		<hr/>";

	stream << "<table style=\"margin-left: 20px;\">";
	stream << "	<tr style=\"height: 30px\">";
	stream << "		<td valign=\"top\">";
	stream << "			<span class=\"head3\">Name:&nbsp;&nbsp;&nbsp;</span><br/>";
	stream << "		</td>";
	stream << "		<td>";
	stream << "			<input class=\"inputText\" type=\"text\" id=\"confName\" name=\"confName\" value=\"" << configuration.getName() << "\" /><br/>";
	stream << "		</td>";
	stream << "	</tr>";
	stream << "	<tr style=\"height: 30px\">";
	stream << "		<td valign=\"top\">";
	stream << "			<span class=\"head3\">Description:&nbsp;&nbsp;&nbsp;</span><br/>";
	stream << "		</td>";
	stream << "		<td>";
	stream << "			<textarea class=\"inputTextArea\" type=\"text\" id=\"confDescription\" name=\"confDescription\" rows=\"4\" >" << configuration.getDescription() << "</textarea><br/>";
	stream << "		</td>";
	stream << "	</tr>";
	stream << "	<tr style=\"height: 30px\">";
	stream << "		<td></td>";
	stream << "		<td align=\"center\">";
	stream << "			<input type=\"button\" value=\"Save\" style=\"width:60px;\" onclick=\"javascript: $('loading').style.visibility='visible'; SConfigurations.saveConfiguration(" << configuration.getID() << ",$('confName').value,$('confDescription').value,redrawLayer);\" />&nbsp;&nbsp;|&nbsp;&nbsp;<a href=\"/configurations.html#show#" << configuration.getID() << "\" class=\"cancelLink\">Cancel<a>";
	stream << "		</td>";
	stream << "	</tr>";
	stream << "</table>";
	stream << "	<br/>";
	stream << "	<div id=\"errorMessage\"></div></";
	stream << "	<br/>";
	stream << "	</td></tr>";
	stream << "</table>";
	result.push_back(divID);
	result.push_back(stream.str());

	return result;
}

std::vector<std::string> SConfigurations::getConfigurationHtml(std::string divID, int configurationID)
{
	std::stringstream stream;
	std::vector<std::string> result;

	if(!DataBase::getInstance()->existsConfiguration(configurationID))
	{
		result.push_back(divID);
		result.push_back(stream.str());
		result.push_back("window.location = '/configurations.html';");
		return result;
	}

	Configuration configuration = DataBase::getInstance()->getConfiguration(configurationID);

	stream << "<table width=\"1024\">";
	stream << "	<tr><td>";

	stream << "		<br/>";

	stream << "		<div style=\"overflow: hidden; margin-left: 10px;\">";
	stream << "			<span class=\"head1\">Configurations :: " << configuration.getName() << "</span><br/>";
	stream << "			<span style=\"float:left; margin-left: 10px; margin-top: 5px;\"><a href=\"/configurations.html#edit#" << configuration.getID() << "\" class=\"textLink\">[edit]</a></span>&nbsp;&nbsp;";
	stream << "			<span style=\"float:left; margin-left: 10px; margin-top: 5px;\"><a href=\"javascript: if(confirm('Are you sure you want to delete this configuration?')){$('loading').style.visibility='visible'; SConfigurations.removeConfiguration(" << configurationID << ",executeScriptLoading);}\" class=\"textLink\">[delete]</a></span>";
	stream << "		</div>";

	stream << "		<hr/>";

	stream << "		<div style=\"margin-left: 20px;\">";
	stream << "			<span class=\"head3\">Name:&nbsp;</span><span class=\"text\">" << configuration.getName() << "</span><br/>";
	stream << "			<span class=\"head3\">Created on:&nbsp;</span><span class=\"text\">" << rgcpp::ToString(configuration.getCreation(),"%Y-%m-%d %X") << "</span><br/>";
	stream << "			<span class=\"head3\">Last update on:&nbsp;</span><span class=\"text\">" << rgcpp::ToString(configuration.getUpdated(),"%Y-%m-%d %X") << "</span><br/>";
	stream << "			<span class=\"head3\">Used in:&nbsp;</span><span class=\"text\">" << DataBase::getInstance()->getConfigurationDevicesCount(configurationID) << " devices</span><br/>";
	stream << "			<table style=\"margin-left: -1px;\"><tr>";
	stream << "			<td valign=\"top\"><span class=\"head3\">Description:&nbsp;</span></td>";
	stream << "			<span class=\"head3\">Description:&nbsp;</span><span class=\"text\">" << configuration.getDescription() << "</span><br/><br/>";
	stream << "			<tr></table>";

	stream << "		</div>";

	stream << "		<hr/>";

	stream << "		<div id=\"backupRestoreFile\" style=\"margin-left: 20px;\">";
	stream << "			<span class=\"head2\">Backup/Restore File</span><br/><br/>";
	std::string fileName = configuration.getConfigFileName();
	std::string destFile = ACSConfig::getDataDirectory()+std::string("Configuration_BackupRestore_")+rgcpp::ToString(configurationID);
	if(!fileName.empty() && boost::filesystem::exists(destFile))
	{
		stream << "			<span class=\"head3\">File:&nbsp;</span><span class=\"text\">" << fileName << "</span><br/>";
		stream << "			<span class=\"head3\">Release:&nbsp;</span><span class=\"text\">" << configuration.getCFRelease() << "</span><br/>";
		stream << "			<span class=\"head3\">Type:&nbsp;</span><span class=\"text\">" << configuration.getCFType() << "</span><br/>";
		stream << "			<span class=\"head3\">Size:&nbsp;</span><span class=\"text\">" << rgcpp::ToStringHumanReadable(boost::filesystem::file_size(destFile)) << "</span><br/>";
		stream << "			<span class=\"head3\">Backup created on:&nbsp;</span><span class=\"text\">" << configuration.getCFCreation() << "</span><br/>";
		stream << "			<span class=\"head3\">Master license:&nbsp;</span><span class=\"text\">" << configuration.getCFLicenseID() << "</span><br/>";
		stream << "			<span class=\"head3\">Need reboot:&nbsp;</span><span class=\"text\">" << configuration.getCFReboot() << "</span><br/>";
		stream << "			<span class=\"head3\">With voip sounds:&nbsp;</span><span class=\"text\">" << configuration.getCFVoipSounds() << "</span><br/>";
		stream << "			<span class=\"head3\">Backup description:&nbsp;</span><span class=\"text\">" << configuration.getCFDescription() << "</span><br/><br/>";
		stream << "			<input type=\"button\" value=\"Clear File\" style=\"width:120px;\" onclick=\"javascript: if(confirm('Are you sure you want to clear backup/restore file?')){$('loading').style.visibility='visible'; SConfigurations.clearConfigurationBackupRestoreFile('backupRestoreFile'," << configuration.getID() << ",redrawLayer);}\" />";
		stream << "			<br/><br/>";
	}
	stream << "			<form method=\"POST\" enctype=\"multipart/form-data\" action='/FileUpload?type=1&id=" << configurationID << "'>";
	stream << "				<span class=\"head3\">Upload new file:&nbsp;</span>";
	stream << "				<input id=\"upfile\" name=\"upfile\" type=\"file\" class=\"text\" />&nbsp;&nbsp;<input type=\"submit\" value=\"Upload\" style=\"width:60px;\"/>";
	stream << "			</form>";

	stream << "			<br/>";
	stream << "		</div>";

//	stream << "		<hr/>";

//	stream << "		<div id=\"commandList\" style=\"margin-left: 10px;\">";
//	stream << 			SConfigurations::getConfigurationCommandHtml(configuration.getID());
//	stream << "		</div>";

	stream << "	</td></tr>";
	stream << "</table>";

	result.push_back(divID);
	result.push_back(stream.str());

	return result;
}

std::string SConfigurations::getConfigurationCommandHtml(int configurationID)
{
	std::stringstream stream;

	stream << "			<span class=\"head2\">Command List</span><br/><br/>";

	std::vector<std::string> arguments;
	std::vector<Command> commands = DataBase::getInstance()->getConfigurationCommands(configurationID);
	for(std::vector<Command>::iterator itr=commands.begin(); itr!=commands.end(); itr++)
	{
		stream << "		<a href=\"javascript: $('loading').style.visibility='visible'; SConfigurations.removeConfigurationCommand('commandList'," << configurationID << "," << itr->getIndex() << ",redrawLayer);\" class=\"textLink\">[x]</a>&nbsp;";
		if(itr->getIndex() == 0)
			stream << "		<span class=\"disableTextLink\">[up]</span>&nbsp;";
		else
			stream << "		<a href=\"javascript: $('loading').style.visibility='visible'; SConfigurations.switchConfigurationCommand('commandList'," << configurationID << "," << itr->getIndex() << "," << itr->getIndex() - 1 << ",redrawLayer);\" class=\"textLink\">[up]</a>&nbsp;";
		if(itr->getIndex() == commands.size()-1)
			stream << "		<span class=\"disableTextLink\">[down]</span>&nbsp;";
		else
			stream << "		<a href=\"javascript: $('loading').style.visibility='visible'; SConfigurations.switchConfigurationCommand('commandList'," << configurationID << "," << itr->getIndex() << "," << itr->getIndex() + 1 << ",redrawLayer);\" class=\"textLink\">[down]</a>&nbsp;";
		stream << "		&nbsp;<span class=\"text\" style=\"font-weight: bold;\" >" << itr->getCommand() << "</span>&nbsp;";
		arguments = itr->getArguments();
		for(std::vector<std::string>::iterator itr2=arguments.begin(); itr2!=arguments.end(); itr2++)
			stream << "		<span class=\"text\">" << *itr2 << "</span>&nbsp;";
		stream << "		<br/>";
	}
	stream << "		<br/>";

	stream << "			<input class=\"inputText\" type=\"text\" style=\"width:435px; height:20px; font-size: 12px;\" id=\"commandInput\" name=\"commandInput\" onkeypress=\"javascript: if(checkEnter(event)){$('loading').style.visibility='visible';  SConfigurations.addConfigurationCommand('commandList'," << configurationID << ",$('commandInput').value,redrawLayer);}\"/>&nbsp;&nbsp;";
	stream << "			<input type=\"button\" value=\"Add Command\" style=\"width:120px;\" onclick=\"javascript: $('loading').style.visibility='visible'; SConfigurations.addConfigurationCommand('commandList'," << configurationID << ",$('commandInput').value,redrawLayer);\" />";

	return stream.str();
}

}
